﻿// Copyright (c)  MOKEYISH. All rights reserved.
// Licensed under the MIT License, See License.txt in the project root for license information.

using System;

namespace NSQL.Expressions
{
    public class ConstantExpression : BaseExpression, IConstantExpression
    {
        private readonly object _value;
        public virtual object ValueOf() => _value;
        protected ConstantExpression(object value) => _value = value;

        protected ConstantExpression()
        {
        }

        #region [value cast]

        public static explicit operator ConstantExpression(bool val) => (BooleanExpression) val;

        public static implicit operator ConstantExpression(byte val) => new ConstantExpression(val);

        public static implicit operator ConstantExpression(char val) => new ConstantExpression(val);

        public static implicit operator ConstantExpression(decimal val) => new ConstantExpression(val);

        public static implicit operator ConstantExpression(double val) => (NumericExpression) val;

        public static implicit operator ConstantExpression(float val) => (NumericExpression) val;

        public static implicit operator ConstantExpression(short val) => (IntegerExpression) val;

        public static implicit operator ConstantExpression(int val) => (IntegerExpression) val;

        public static implicit operator ConstantExpression(long val) => (NumericExpression) (double) val;

        public static implicit operator ConstantExpression(Guid val) => new ConstantExpression(val);

        public static implicit operator ConstantExpression(string val) => (StringExpression) val;

        public static implicit operator ConstantExpression(DateTime val) => (DateTimeExpression) val;

        public static implicit operator ConstantExpression(TimeSpan val) => new ConstantExpression(val);

        public static implicit operator ConstantExpression(byte[] val) => new ConstantExpression(val);
        
        #endregion

#if true

        #region [operator override]

        public static ConstantExpression operator + (ConstantExpression v1, ConstantExpression v2)
        {
            var o1 = v1.ValueOf();
            var o2 = v2.ValueOf();
            var dyn = (dynamic) o1 + (dynamic) o2;
            return (ConstantExpression) dyn;
        }

        public static ConstantExpression operator -(ConstantExpression v1, ConstantExpression v2)
        {
            var o1 = v1.ValueOf();
            var o2 = v2.ValueOf();
            var dyn = (dynamic) o1 - (dynamic) o2;
            return (ConstantExpression) dyn;
        }

        public static ConstantExpression operator -(ConstantExpression v1)
        {
            var o1 = v1.ValueOf();
            var dyn = -(dynamic) o1;
            return (ConstantExpression) dyn;
        }

        public static ConstantExpression operator *(ConstantExpression v1, ConstantExpression v2)
        {
            var o1 = v1.ValueOf();
            var o2 = v2.ValueOf();
            var dyn = (dynamic) o1 * (dynamic) o2;
            return (ConstantExpression) dyn;
        }

        public static ConstantExpression operator /(ConstantExpression v1, ConstantExpression v2)
        {
            var o1 = v1.ValueOf();
            var o2 = v2.ValueOf();
            var dyn = (dynamic) o1 / (dynamic) o2;
            return (ConstantExpression) dyn;
        }

        public static ConstantExpression operator %(ConstantExpression v1, ConstantExpression v2)
        {
            var o1 = v1.ValueOf();
            var o2 = v2.ValueOf();
            var dyn = (dynamic) o1 % (dynamic) o2;
            return (ConstantExpression) dyn;
        }

        #endregion

#endif
        public override T Accept<T>(IExpressionVisitor<T> visitor) => visitor.Visit(this);
    }
}